<html>
<head>
</head>
<body>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/JavaScript" src="./js/lib/jsDraw2D.js"></script>
<script type="text/JavaScript" src="./js/drawing.js"></script>
<script type="text/JavaScript" src="./js/lib/math.min.js"></script>
<script type="text/JavaScript" src="./js/TestPlane.js"></script>
<script type="text/JavaScript" src="./js/Logistic_Regression.js"></script>
<div id="control">
  <div>
    <label for="N">N = </label>
    <input type="text" name="N" id="N" value="100" size="10" />
    <label for="testTimes">Test times = </label>
    <input type="text" name="testTimes" id="testTimes" value="100" size="10" />
    <label for="eta">eta = </label>
    <input type="text" name="eta" id="eta" value="0.01" size="10" />
  </div>
  <br />
  <div>
    <button id="lr_anim">Animate Logistic Regression(by point)</button>
  </div>
  <div>
    <button id="lr_anim_epoch">Animate Logistic Regression(by epoch)</button>
  </div>
  <div>
    <button id="lr_test_times">Test Logistic Regression Multiple Times</button>
  </div>
  <div>
    <button id="stop">Stop</button>
  </div>
</div>
<div style="position:relative;">
  <div style="position:absolute; width: 400px;">
    <textarea id="status" readonly rows="30" cols="40"></textarea>
  </div>
  <div id="canvas" style="position:absolute; width:500px;height:500px;left:400px" />
</div>
<script type="text/JavaScript">
  var numberOfErrorTestPoint = 1000;

  var add_w0 = function(point) {
    return [1,
            point[0],
            point[1]];
  };

  window.generateDataSet = function(NumberOfN, plane) {
    var result = [];
    for(var i = 0; i < NumberOfN; i++) {
      var point = plane.randomPoint();
      var output = plane.getOutput(point);
      result.push({point: point, output: output});
    }
    return result;
  }

  window.transformDataSet = function(dataSet, transformFunction) {
    var result = [];
    for(var i in dataSet) {
      result.push({point: transformFunction(dataSet[i].point), output: dataSet[i].output});
    }
    return result;
  }





  window.animateLogisticRegression = function(NumberOfN, eta) {
    var plane = new window.TestPlane(-1,1,-1,1);
    var dataSet = window.generateDataSet(NumberOfN, plane);
    var dataSetWithw0 = window.transformDataSet(dataSet, add_w0);

    var logisticRegression = new window.Logistic_Regression();
    logisticRegression.initializeLearning(dataSetWithw0, [0,0,0], eta, 0.01);

    var completeCallback = function(norm_history, weights_history, epoch) {
      window.initCanvas();
      window.drawTargetLine(plane)
      window.drawDataSet(dataSet);
      window.drawRegressionResult(weights_history[weights_history.length -1], plane);

      var EoutDataSet = window.transformDataSet(window.generateDataSet(numberOfErrorTestPoint, plane), add_w0);
      var Eout = logisticRegression.Eout(EoutDataSet);
      window.displayResult(norm_history, weights_history, epoch, Eout);
    };

    var stepCallback = function(data, norm, weights, norm_history, weights_history, epoch, remaining_points) {
      window.initCanvas();
      window.drawTargetLine(plane)
      window.drawDataSet(dataSet);
      window.drawRegressionStatus(weights, weights_history, data.point, plane);

      window.displayStatus(norm, weights, norm_history[norm_history.length - 1], weights_history[weights_history.length - 1], epoch, remaining_points);
      window.timer = setTimeout(function() {logisticRegression.stochasticGradientDescentStep(stepCallback, null, completeCallback);}, 50);
    };

    window.initCanvas();
    logisticRegression.stochasticGradientDescentStep(stepCallback, null, completeCallback);
  }

  window.animateLogisticRegressionEpoch = function(NumberOfN, eta) {
    var plane = new window.TestPlane(-1,1,-1,1);
    var dataSet = window.generateDataSet(NumberOfN, plane);
    var dataSetWithw0 = window.transformDataSet(dataSet, add_w0);

    var logisticRegression = new window.Logistic_Regression();
    logisticRegression.initializeLearning(dataSetWithw0, [0,0,0], eta, 0.01);

    var completeCallback = function(norm_history, weights_history, epoch) {
      window.initCanvas();
      window.drawTargetLine(plane)
      window.drawDataSet(dataSet);
      window.drawRegressionResult(weights_history[weights_history.length -1], plane);

      var EoutDataSet = window.transformDataSet(window.generateDataSet(numberOfErrorTestPoint, plane), add_w0);
      var Eout = logisticRegression.Eout(EoutDataSet);
      window.displayResult(norm_history, weights_history, epoch, Eout);
    };

    var epochCallback = function(norm_history, weights_history, epoch) {
      window.initCanvas();
      window.drawTargetLine(plane)
      window.drawDataSet(dataSet);
      window.drawRegressionEpoch(weights_history, plane);

      window.displayEpoch(norm_history, weights_history, epoch);
      window.timer = setTimeout(function() {logisticRegression.stochasticGradientDescentEpochStep(epochCallback, completeCallback);}, 50);
    };

    window.initCanvas();
    logisticRegression.stochasticGradientDescentEpochStep(epochCallback, completeCallback);
  }
  
  window.testLogisticRegressionMultipleTimes = function(NumberOfN, eta, times) {
    var logisticRegression = new window.Logistic_Regression();

    var totalEout = 0;
    var totalEpoch = 0;
    var currentTimes = 0;
    var plane;
    var newTest;
    var completeCallback;
    var dataSet;
    var dataSetWithw0;

    newTest = function() {
      plane = new window.TestPlane(-1,1,-1,1);
      dataSet = window.generateDataSet(NumberOfN, plane);
      dataSetWithw0 = window.transformDataSet(dataSet, add_w0);
      logisticRegression.initializeLearning(dataSetWithw0, [0,0,0], eta, 0.01);
      logisticRegression.stochasticGradientDescent(completeCallback);
    }

    completeCallback = function(norm_history, weights_history, epoch) {
      window.initCanvas();
      window.drawTargetLine(plane)
      window.drawDataSet(dataSet);
      window.drawRegressionResult(weights_history[weights_history.length -1], plane);

      var EoutDataSet = window.transformDataSet(window.generateDataSet(numberOfErrorTestPoint, plane), add_w0);
      var Eout = logisticRegression.Eout(EoutDataSet);

      totalEout += Eout;
      totalEpoch += epoch;
      currentTimes += 1;

      if(currentTimes < times) {
        var status = 'Test: ' + currentTimes + '\r\n'
                   + 'epoch: ' + epoch + '\r\n'
                   + 'Eout: ' + Eout;
        $('#status').val(status);

        window.timer = setTimeout(function() {newTest();}, 1);
      } else {
        var avgEout = totalEout / times;
        var avgEpoch = totalEpoch / times;
        var status = 'Average epoch: ' + avgEpoch + '\r\n'
                   + 'Average Eout: ' + avgEout;
        $('#status').val(status);
      }
    };

    window.initCanvas();
    newTest();
  }





  window.displayStatus = function(norm, current_weights, previous_norm, previous_weights, epoch, remaining_points) {
    var status = 'epoch: ' + epoch + '\r\n\r\n'
               + 'weights of previous epoch: ' + '\r\n' + window.joinWithRounding(previous_weights, 6) + '\r\n'
               + 'norm of previous epoch: ' + '\r\n' + previous_norm + '\r\n\r\n'
               + 'weights: ' + '\r\n' + window.joinWithRounding(current_weights, 6) + '\r\n'
               + 'norm: ' + '\r\n' + norm + '\r\n\r\n'
               + 'Remaining points of this epoch: ' + remaining_points;
    $('#status').val(status);
  }

  window.displayEpoch = function(norm_history, weights_history, epoch) {
    var current_weights = weights_history[weights_history.length - 1];
    var previous_weights = weights_history[weights_history.length - 2];

    var status = 'epoch: ' + epoch + '\r\n\r\n'
               + 'weights: ' + '\r\n' + window.joinWithRounding(current_weights, 6) + '\r\n\r\n'
               + 'weights of previous epoch: ' + '\r\n' + window.joinWithRounding(previous_weights, 6) + '\r\n\r\n'
               + 'norm: ' + norm_history[norm_history.length - 1];
    $('#status').val(status);
  }

  window.displayResult = function(norm_history, weights_history, epoch, Eout) {
    var result_weights = weights_history[weights_history.length -1];

    var last_5_weights = '';
    var last_5_norm = '';

    for(var i = 0; i < Math.min(5, weights_history.length - 2); i++) {
      last_5_weights += window.joinWithRounding(weights_history[weights_history.length - 2 - i], 6) + '\r\n';
      last_5_norm += norm_history[norm_history.length - 2 - i] + '\r\n';
    }

    var status = 'total epoch: ' + epoch + '\r\n'
               + 'Eout: ' + Eout + '\r\n'
               + 'weights: ' + '\r\n' + window.joinWithRounding(result_weights, 6) + '\r\n\r\n'
               + 'norm: ' + norm_history[norm_history.length - 1] + '\r\n\r\n'
               + 'last 5 weights: ' + '\r\n' + last_5_weights + '\r\n\r\n'
               + 'last 5 norm: ' + '\r\n' + last_5_norm + '\r\n\r\n';

    $('#status').val(status);
  }

  window.drawRegressionStatus = function(current_weights, weights_history, training_point, plane) {
    if(weights_history.length > 1) {
      var secondLastEpochWeightsLine = window.weightsToLine(weights_history[weights_history.length -2], plane);
      window.plotLine(secondLastEpochWeightsLine, pinkPen);
    }

    var lastEpochWeightsLine = window.weightsToLine(weights_history[weights_history.length - 1], plane);
    window.plotLine(lastEpochWeightsLine, pinkPen2);

    var currentWeightsLine = window.weightsToLine(current_weights, plane);
    window.plotLine(currentWeightsLine, greenPen);

    window.plotCircle([training_point[1], training_point[2]], orangePen);
  }

  window.drawRegressionEpoch = function(weights_history, plane) {
    if(weights_history.length > 2) {
      var secondLastEpochWeightsLine = window.weightsToLine(weights_history[weights_history.length -3], plane);
      window.plotLine(secondLastEpochWeightsLine, pinkPen);
    }

    if(weights_history.length > 1) {
      var lastEpochWeightsLine = window.weightsToLine(weights_history[weights_history.length - 2], plane);
      window.plotLine(lastEpochWeightsLine, pinkPen2);
    }

    var currentWeightsLine = window.weightsToLine(weights_history[weights_history.length - 1], plane);
    window.plotLine(currentWeightsLine, greenPen);
  }

  window.drawRegressionResult = function(result_weights, plane) {
    var resultWeightsLine = window.weightsToLine(result_weights, plane);
    window.plotLine(resultWeightsLine, greenPen);

  }

  window.stop = function() {
    clearTimeout(window.timer);
  }

  window.initCanvas();
  $('#lr_anim').on('click', function() { window.animateLogisticRegression($('#N').val(), parseFloat($('#eta').val())); });
  $('#lr_anim_epoch').on('click', function() { window.animateLogisticRegressionEpoch($('#N').val(), parseFloat($('#eta').val())); });
  $('#lr_test_times').on('click', function() { window.testLogisticRegressionMultipleTimes($('#N').val(), parseFloat($('#eta').val()), $('#testTimes').val()); });

  $('#stop').on('click', function() { window.stop(); });
</script>